package gui;
import generator.GraphGenerator;
import generator.XmiGenerator;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.io.File;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;

import model.Model;

import org.jgrapht.graph.DefaultEdge;

import parser.ZbjParser;

import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxGeometry;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.util.mxConstants;

/***
 * Class for the User Interface, with a fileChooser and a convert button
 * @author Federico
 *
 */
public class GUI extends JFrame{

	private static final long serialVersionUID = 1L;
	public static final double DividerPos = 0.8;

    public GUI()
    {
        this.buildGui();
    }

    public void onOpen()
    {
        fileChooser = new JFileChooser();
        fileChooser.setApproveButtonText("Open Zbj");
        fileChooser.setAcceptAllFileFilterUsed(false);
        fileChooser.addChoosableFileFilter(new ZbjFilter());
        int returnVal = fileChooser.showOpenDialog(null);
        getContentPane().add(fileChooser);
        fileChooser.setVisible(false);
        
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            selectedFile = fileChooser.getSelectedFile();
            txtOutput.setText("File opened, name: "+selectedFile.getName());
            hideOptions(true);
        } else {
            txtOutput.setText("No file opened");
        }
    }

    public void onClose()
    {
        if(selectedFile != null){
            selectedFile = null;
            cleanLay();
            txtOutput.setText("Please, select a file");
            hideOptions(false);
        }
    }

    public void onHelp()
    {
        JOptionPane.showMessageDialog(this, "First of all you have to open a zbj file. Then click in View->Convert and you will see"
                + "\na diagrama with the objects that the application discovered.\nThe XMI file, that was generated, is in the same "
                + "directory of the zbj file.\nNow, you can open it with an UML Tool like ArgoUML, Umbrello, etc.");
    }

    public void onAbout()
    {
        JOptionPane.showMessageDialog(this, "This application was developed as a PFC at the ESEI, University of Vigo. (2013)");
    }

    public void onQuit()
    {
        System.exit(0);
    }
    
    public void onView()
    {
        if(selectedFile == null){
            JOptionPane.showMessageDialog(this,
                "You have to open a zbj file to get an XMI file and a preview diagram.",
                "Error",
                JOptionPane.ERROR_MESSAGE);
        }else{
        	cleanLay();
            convertFile();
        }
    }
    
    private void cleanLay(){
    	txtOutput.setText("");
    	pnlDrawingOutput.removeAll();
    }
    
    private void convertFile(){
        ZbjParser zbj = new ZbjParser();
        zbj.doParse(selectedFile);
        Model m = zbj.getModel();
        if(m.isValid()){
	        txtOutput.setText(m.toString());
	        generateGraphic(m);
	        String dir = selectedFile.getAbsolutePath();
	        dir = dir.substring(0,dir.lastIndexOf(File.separator));
	        XmiGenerator gen = new XmiGenerator(m, dir);
	        gen.generate();
        }else{
        	txtOutput.setText("Corrupted file, choose anotherone");
        }
    }
    
    private void generateGraphic(Model m){
        //Graphic generator
        GraphGenerator g = new GraphGenerator(m);
        g.generate();
        JGraphXAdapter<String, DefaultEdge> graph = new JGraphXAdapter<String, DefaultEdge>(g.getGraph());
		        
        mxGraphComponent graphComponent = new mxGraphComponent(graph);

        graph.getModel().beginUpdate();
        double x = 35, y = 35;
        for (mxCell cell : graph.getVertexToCellMap().values()) {
            graph.getModel().setGeometry(cell, new mxGeometry(x, y, 95, 50));
            x += 135;
            if (x > 350) {
                x = 35;
                y += 120;
            }
        }
        //Can't make connections
        graphComponent.setConnectable(false);

        graphComponent.getGraph().setCellsEditable(false);

        //Can't edit the label, the size and the position of the nodes
        graph.getStylesheet().getDefaultVertexStyle().put(mxConstants.STYLE_EDITABLE, "0");
        graph.getStylesheet().getDefaultVertexStyle().put(mxConstants.STYLE_MOVABLE, "0");
        graph.getStylesheet().getDefaultVertexStyle().put(mxConstants.STYLE_RESIZABLE, "0");

        //Can't edit the size and the position and remove the labels of the edges
        graph.getStylesheet().getDefaultEdgeStyle().put(mxConstants.STYLE_NOLABEL, "1");
        graph.getStylesheet().getDefaultEdgeStyle().put(mxConstants.STYLE_RESIZABLE, "0");

        graph.getModel().endUpdate();

        pnlDrawingOutput.add(graphComponent);
        pnlDrawingOutput.revalidate();
                        
    }

    private void buildStatusBar()
    {
        this.tbStatus = new JToolBar();
        this.lblPosition = new JLabel();
        this.lblStatus = new JLabel();
        this.tbStatus.setBorder( javax.swing.BorderFactory.createBevelBorder( javax.swing.border.BevelBorder.LOWERED ) );
        this.tbStatus.setFloatable( false );
        this.tbStatus.setRollover( true );

        this.lblPosition.setText( "0:0" );
        this.tbStatus.add( this.lblPosition );
        this.tbStatus.add( new JLabel( " | ") );
        this.tbStatus.add( this.lblStatus );
    }

    private void buildMenu()
    {
        mMainMenu = new javax.swing.JMenuBar();
        mFile = new javax.swing.JMenu();
        opOpen = new javax.swing.JMenuItem();
        opClose = new javax.swing.JMenuItem();
        opQuit = new javax.swing.JMenuItem();
        mView = new javax.swing.JMenu();
        mHelp = new javax.swing.JMenu();
        opHelp = new javax.swing.JMenuItem();
        opAbout = new javax.swing.JMenuItem();
        opGen = new javax.swing.JMenuItem();

        mFile.setMnemonic('f');
        mFile.setText("File");
        mFile.setName("mFile");

        opOpen.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
        opOpen.setMnemonic('o');
        opOpen.setText("Open");
        opOpen.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                GUI.this.onOpen();
            }
        });
        mFile.add(opOpen);

        opClose.setMnemonic('c');
        opClose.setText("Close");
        opClose.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                GUI.this.onClose();
            }
        });
        mFile.add(opClose);

        opQuit.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Q, java.awt.event.InputEvent.CTRL_MASK));
        opQuit.setMnemonic('q');
        opQuit.setText("Quit");
        opQuit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
            	GUI.this.onQuit();
            }
        });
        mFile.add(opQuit);

        mMainMenu.add( mFile );

        mView.setMnemonic( 'v' );
        mView.setText( "View" );
        opGen.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_G, java.awt.event.InputEvent.CTRL_MASK));
        opGen.setMnemonic('g');
        opGen.setText("Generate");
        opGen.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
            	GUI.this.onView();
            }
        });
        mView.add(opGen);

        mMainMenu.add( this.mView );

        mHelp.setMnemonic('h');
        mHelp.setText("Help");

        opHelp.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F1, 0));
        opHelp.setMnemonic('h');
        opHelp.setText("Help");
        opHelp.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
            	GUI.this.onHelp();
            }
        });
        mHelp.add(opHelp);

        opAbout.setMnemonic('a');
        opAbout.setText("About");
        opAbout.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
            	GUI.this.onAbout();
            }
        });
        mHelp.add(opAbout);

        mMainMenu.add(mHelp);
        
        hideOptions(false);

        this.setJMenuBar( mMainMenu );
    }

    private void buildOutput()
    {
        this.txtOutput = new javax.swing.JTextArea();
        this.txtOutput.setColumns( 20 );
        this.txtOutput.setEditable( false );
        this.txtOutput.setFont( new Font("Courier New", 2, 14 ) );
        this.txtOutput.setForeground( new Color(153, 51, 0) );
        this.txtOutput.setRows( 5 );
        this.txtOutput.setBackground( Color.lightGray );

        this.spOutputScrollerText = new JScrollPane();
        this.spOutputScrollerText.setViewportView( this.txtOutput );
        this.spOutputScrollerText.setMinimumSize( new Dimension( 500, 150 ) );
        
        
        this.pnlDrawingOutput = new JPanel();
        this.spOutputScrollerDrawing = new JScrollPane();
        this.spOutputScrollerDrawing.setViewportView( this.pnlDrawingOutput );
        this.spOutputScrollerDrawing.setMinimumSize( new Dimension( 500, 150 ) );
        
    }
    
    private void hideOptions(boolean value){
    	opClose.setEnabled(value);
    	opGen.setEnabled(value);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     */
    private void buildGui()
    {
        // Prepare main window events
        setDefaultCloseOperation( javax.swing.WindowConstants.EXIT_ON_CLOSE );

        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
            	GUI.this.onQuit();
            }
        });

        // Create main widgets
        this.buildStatusBar();
        this.buildMenu();
        this.buildOutput();

        //this.pnlDrawingOutput = new JPanel();
        this.spPanelDivision = new JSplitPane( JSplitPane.VERTICAL_SPLIT, this.spOutputScrollerDrawing, this.spOutputScrollerText );
        this.spPanelDivision.setOneTouchExpandable( false );
        this.spPanelDivision.setResizeWeight( DividerPos );

        // Layout
        this.getContentPane().setLayout( new BorderLayout() );
        this.getContentPane().add( this.spPanelDivision, BorderLayout.CENTER  );
        this.getContentPane().add( this.tbStatus, BorderLayout.SOUTH );

        this.setMinimumSize( new Dimension( 620, 450 ) );
        this.pack();
        
    }
    
    private JLabel lblPosition;
    private JLabel lblStatus;
    private JMenu mFile;
    private JMenu mHelp;
    private JMenuBar mMainMenu;
    private JMenu mView;
    private JMenuItem opAbout;
    private JMenuItem opClose;
    private JMenuItem opHelp;
    private JMenuItem opOpen;
    private JMenuItem opGen;
    private JMenuItem opQuit;
    private JSplitPane spPanelDivision;
    private JScrollPane spOutputScrollerText;
    private JScrollPane spOutputScrollerDrawing;
    private JToolBar tbStatus;
    private JTextArea txtOutput;
    private JPanel pnlDrawingOutput;
    private JFileChooser fileChooser;
    private File selectedFile = null;
}
